#pragma once
#include <pthread.h>
#include <iostream>
#include <queue>
//blockingQueue实现生产者消费者模型:多生产者，多消费者
//队列为空时，必须先生产；队列为满时，必须先消费；中间状态，消费和生产均可——>并发运行
template<class T>
class BlockingQueue
{
    public:
    BlockingQueue(int capacity = 5):_capacity(capacity),_wait_c(0),_wait_p(0)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_c_cond,nullptr);
        pthread_cond_init(&_p_cond,nullptr);
    }

    bool IsFull()
    {
        return _q.size() == _capacity;
    }

    bool IsEmpty()
    {
        return _q.empty();
    }

    //生产者
    void Push(const T& data)
    {
        pthread_mutex_lock(&_mutex);
        while(IsFull())
        {
            _wait_p++;
            pthread_cond_wait(&_p_cond,&_mutex);
            _wait_p--;
        }
        _q.push(data);
        if(_wait_c)
            pthread_cond_signal(&_c_cond);
        pthread_mutex_unlock(&_mutex);
    }

    //消费者，带一个输出型参数
    //尽量不要使用引用
    void Pop(T* out)
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {
            _wait_c++;
            pthread_cond_wait(&_c_cond,&_mutex);
            _wait_c--;
        }
        *out = _q.front();
        _q.pop();       
        if(_wait_p)
            pthread_cond_signal(&_p_cond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockingQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }
    private:
    std::queue<T> _q;//原始FIFO结构
    int _capacity;
    pthread_mutex_t _mutex;//只用一个互斥锁维护即可
    pthread_cond_t _c_cond;//消费者对应的条件变量
    pthread_cond_t _p_cond;//生产者对应的条件变量
    int _wait_p;//等待的生产者数
    int _wait_c;//等待的消费者数
};